/*
 * Lucas McDaniel
 * GSoC '11
 * HoneyViz
 * 
 * This class generates the primary visualization for the standard view.  There
 * are two images used as backdrops for this which can be interchanged through
 * the menu options.  When the sliding bar is at either extremity the map shows
 * statistics grouped over the entire sensor duration.  When the sliding bar 
 * is at any point in between (within 5% of either side), it shows the closest 
 * time interval that correlates with the line bar (if that secondary 
 * visualization is selected).
 * 
 * All dots are generated off of a logarithmic scale with the largest dot 
 * statically set to 10 pixels and the smallest dot at least 2 pixels.  If 
 * the cumulative modification is selected then the largest size is changed to 
 * 35 pixels with the alpha decreasing the further away from the origin it is 
 * located.
 * 
 * Should not be static with resizing
 */

import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.swing.*;
import java.util.*;

public class MapJPanel extends JPanel{
    
    private Image background_geo, background_pol, background_clear, background;
    private boolean cacheCategory, cacheEnds;
    private String[] cacheEvents;
    private ArrayList cacheResults;
    private double[] currentArr;
    
    public MapJPanel()
    {
        try
        {
            background_geo = new ImageIcon(new URL(AppletState.url + "images/geographical.jpg")).getImage();
            background_pol = new ImageIcon(new URL(AppletState.url + "images/political.jpg")).getImage();
        }
        catch (Exception e){}
        background = background_geo;
        if (background == null)
            System.out.println("NULL");
        Dimension size = new Dimension(background.getWidth(null), background.getHeight(null));
        setPreferredSize(size);
        setMinimumSize(size);
        setMaximumSize(size);
        setSize(size);
        setLayout(null);
    }
    
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;
        if (AppletState.getMapType() == 1)
            background = background_geo;
        else if (AppletState.getMapType() == 2)
            background = background_pol;
        g.drawImage(background, 0, 0, this);
        g.setColor(new Color(255, 0, 0, 100));
        AppletState.setSizeX(getWidth());
        AppletState.setSizeY(getHeight());
        ArrayList nameList = EventColorManager.getNameList();
        String[] events = new String[nameList.size()];
        nameList.toArray(events);
        
        int loc = AppletState.getSliderLocation();
        ArrayList result = new ArrayList();
        boolean locAtEnds = loc==0 || loc==100;
        if (AppletState.getPrimarySearch()==0)
        {
            if (locAtEnds)
            {
                if (AppletState.isInFullMapCache(nameList))
                {
                    result = AppletState.getFullMapCache();
                }
                else
                {
                    if (AppletState.isGroupToCategory() || AppletState.isDistinct())
                    {
                        result = HoneyData.groupBy(events, null, null, false, false, true);
                        for (int inc=0; inc<result.size(); inc++)
                            ((DataElement)result.get(inc)).name = "Group";
                    }
                    else
                        result = HoneyData.groupBy(events, null, null, true, false, true);
                    AppletState.makeFullMapCache(nameList, result);
                }
            }
            else
            {
                if (AppletState.isInRectangleCache(nameList))
                    result = AppletState.getRectangleCache();
                else
                {
                    if (AppletState.isGroupToCategory() || AppletState.isDistinct())
                    {
                        result = HoneyData.groupBy(events, null, null, false, true, true);
                        for (int inc=0; inc<result.size(); inc++)
                            ((DataElement)result.get(inc)).name = "Group";
                    }
                    else
                        result = HoneyData.search(events, null, null);
                    AppletState.makeRectangleCache(nameList, result);
                }
            }
        }
        else
        {
            if (locAtEnds)
            {
                if (AppletState.isInFullMapCache(nameList))
                    result = AppletState.getFullMapCache();
                else
                {
                    result = HoneyData.groupBy(null, null, LocationManager.getLocations(events), false, false, true);
                    AppletState.makeFullMapCache(nameList, result);
                }
            }
            else
            {
                if (AppletState.isInRectangleCache(nameList))
                    result = AppletState.getRectangleCache();
                else
                {
                    result = HoneyData.groupBy(null, null, LocationManager.getLocations(events), false, true, true);
                    for (int inc=0; inc<result.size(); inc++)
                        ((DataElement)result.get(inc)).name = "Group";
                    AppletState.makeRectangleCache(nameList, result);
                }
            }
        }
        
        if (result.size()==0)
            return;
        
        ArrayList time_name = new ArrayList();
        ArrayList time_count = new ArrayList();
        ArrayList time_time = new ArrayList();
        ArrayList time_long = new ArrayList();
        ArrayList time_lat = new ArrayList();
        ArrayList time_color = new ArrayList();

        
        ArrayList time_name2 = new ArrayList();
        ArrayList time_count2 = new ArrayList();
        ArrayList time_long2 = new ArrayList();
        ArrayList time_lat2 = new ArrayList();
        
        
        Date first = ((DataElement)result.get(0)).time;
        Date last = first;

        for (int inc=0; inc<result.size(); inc++)
        {
            Date tmp = ((DataElement)result.get(inc)).time;
            if (first.after(tmp))
                first = tmp;
            else if (last.before(tmp))
                last = tmp;
        }
        long currTime = first.getTime() + (last.getTime() - first.getTime())*loc/95;
        Date currentDate = new Date(currTime);
        Calendar c = Calendar.getInstance();
        c.setTime(currentDate);
        
        int day1 = 0, day3 = 0;
        
        int movingAve = -3;
        
        if (AppletState.getTimeInterval()==0)
        {
            day1 = c.get(Calendar.DAY_OF_YEAR);
            c.add(Calendar.DAY_OF_YEAR, movingAve);
            day3 = c.get(Calendar.DAY_OF_YEAR);
        }
        else if (AppletState.getTimeInterval()==1)
        {
            day1 = c.get(Calendar.WEEK_OF_YEAR);
            c.add(Calendar.WEEK_OF_YEAR, movingAve);
            day3 = c.get(Calendar.WEEK_OF_YEAR);
        }
        else if (AppletState.getTimeInterval()==2)
        {
            day1 = c.get(Calendar.MONTH);
            c.add(Calendar.MONTH, movingAve);
            day3 = c.get(Calendar.MONTH);
        }
        else if (AppletState.getTimeInterval()==3)
        {
            day1 = c.get(Calendar.YEAR);
            c.add(Calendar.YEAR, movingAve);
            day3 = c.get(Calendar.YEAR);
        }
        
        for (int inc=0; inc<result.size(); inc++)
        {
            DataElement DE = (DataElement)result.get(inc);
            c.setTime(DE.time);
            int day2 = 0;
            if (AppletState.getTimeInterval()==0)
                day2 = c.get(Calendar.DAY_OF_YEAR);
            else if (AppletState.getTimeInterval()==1)
                day2 = c.get(Calendar.WEEK_OF_YEAR);
            else if (AppletState.getTimeInterval()==2)
                day2 = c.get(Calendar.MONTH);
            else if (AppletState.getTimeInterval()==3)
                day2 = c.get(Calendar.YEAR);
            if ((loc!=0 && loc!=100 && day1 == day2) || (loc==100 || loc==0))
            {
                time_name.add(DE.name);
                if (time_name2.size()>0 && AppletState.isGroupToCategory() && AppletState.isHeat())
                {   
                    boolean found = false;
                    for (int inc2=0; inc2<time_name2.size(); inc2++)
                    {
                        if (DE.name.compareTo((String)time_name2.get(inc2))==0 &&
                                DE.longitude == (Double)time_long2.get(inc2) &&
                                DE.latitude == (Double)time_lat2.get(inc2))
                        {
                            time_count.add(DE.count - (Integer)time_count2.get(inc2)+1);
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                        time_count.add(DE.count);
                }
                else
                    time_count.add(DE.count);
                time_time.add(DE.time);
                time_long.add(DE.longitude);
                time_lat.add(DE.latitude);
                if (AppletState.getPrimarySearch()==0)
                    time_color.add((Color)EventColorManager.getEvent(DE.name).paint);
                else
                    time_color.add((Color)EventColorManager.getEvent(LocationManager.getLocationName(DE)).paint);
            }
            else if (loc!=0 && loc!=100 && day3 == day2 && AppletState.isGroupToCategory() && AppletState.isHeat())
            {
                time_name2.add("Group");
                time_count2.add(DE.count);
                time_long2.add(DE.longitude);
                time_lat2.add(DE.latitude);
            }
        }
        
        Random gen = new Random();
        String current = "";
        if (time_name.size()>0)
            current = (String)time_name.get(0);
        int curr_int = 0;
        EventColor EC = EventColorManager.getEvent(current);
        int plusX = EC.locXOffset;
        int plusY = EC.locYOffset;
        double largest = 1;
        for (int inc=0; inc<time_long.size(); inc++)
        {
            if (largest<((Integer)time_count.get(inc)).intValue())
                largest = ((Integer)time_count.get(inc)).intValue();
        }
        largest = Math.log10(largest);
        BufferedImage buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D gbi = buffer.createGraphics();
        AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f);
        for (int inc=0; inc<time_long.size(); inc++)
        {
            double number = ((Integer)time_count.get(inc)).intValue();
            number = Math.log10(number);
            if (current.compareTo((String)time_name.get(inc))!=0)
            {
                current = (String)time_name.get(inc);
                EC = EventColorManager.getEvent(current);
                plusX = EC.locXOffset;
                plusY = EC.locYOffset;
            }
            int offset = (int)(8*(number/largest))+2;
            if (AppletState.isGroupToCategory() && AppletState.isHeat())
                offset = (int)(35*(number/largest));
            int alpha = AppletState.isDistinct()?192:(int)(192*(number/largest));
            int tempX = makeX(((Double)time_long.get(inc)).doubleValue()) + plusX;
            int tempY = makeY(((Double)time_lat.get(inc)).doubleValue()) + plusY;
            Color tmpClr = (Color)time_color.get(inc);
            if (tmpClr == null || AppletState.isGroupToCategory() || AppletState.isDistinct())
                tmpClr = Color.RED;
            if (AppletState.isGroupToCategory() && AppletState.isHeat())
            {
                int res = 8;
                for (int inc2=0; inc2<res; inc2++)
                {
                    gbi.setColor(new Color(tmpClr.getRed(), tmpClr.getGreen(), tmpClr.getBlue(), alpha/(inc2+1)));
                    gbi.fill(new Ellipse2D.Double(tempX + res/2 - offset*(inc2+1)/(2*res), tempY + res/2 - offset*(inc2+1)/(2*res), offset*(inc2+1)/res, offset*(inc2+1)/res));
                    gbi.setComposite(ac);
                }
            }
            else
            {
                g.setColor(new Color(tmpClr.getRed(), tmpClr.getGreen(), tmpClr.getBlue(), alpha));
                g.fillOval(tempX, tempY, offset, offset);
            }
        }
        if (AppletState.isGroupToCategory() && AppletState.isHeat())
            g2.drawImage(buffer, null, 0, 0);
//        EventColorManager.print();
    }
       
    public int makeX(double x)
    {
        return (int)(getWidth()*(x/360.0+0.5));
    }
    
    public int makeY(double y)
    {
        return (int)(getHeight()*(-y/180.0+0.48));
    }
}
